﻿using NodeBasedSkillEditor.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XDFLib;

namespace NodeBasedSkillEditor.Model.CommandHistory
{
    public class UndoManager : Singleton<UndoManager>
    {
        public int HistoryCount => _cmdHistory.RecordCount;
        public int HistoryCapacity {
            get { return _cmdHistory.RecordCapacity; }
            set { _cmdHistory.RecordCapacity = value; }
        }

        CommandHistory _cmdHistory = new CommandHistory(100);

        //VM_MainWindow _mainWinVM;

        // key = 指令类型， value中的item1表示undo指令，item2表示redo指令
        Dictionary<ECommandType, (Action<CommandRecord>, Action<CommandRecord>)> _commandActions = new();

        //public UndoManager(VM_MainWindow mainWinVM, int historyCapacity = 100)
        //{
        //    _mainWinVM = mainWinVM;
        //    _cmdHistory = new CommandHistory(historyCapacity);
        //}

        public (Action<CommandRecord>, Action<CommandRecord>) GetRegistedCommand(ECommandType cmdType)
        {
            (Action<CommandRecord>, Action<CommandRecord>) result;
            _commandActions.TryGetValue(cmdType, out result);
            return result;
        }

        public bool HasRegisteredCommand(ECommandType cmdType)
        {
            return _commandActions.ContainsKey(cmdType);
        }

        public bool HasRegisteredCommandForUndo(ECommandType cmdType)
        {
            var (undo, redo) = GetRegistedCommand(cmdType);
            return undo != null;
        }

        public bool HasRegisteredCommandForRedo(ECommandType cmdType)
        {
            var (undo, redo) = GetRegistedCommand(cmdType);
            return redo != null;
        }

        public void RegisterCommandUndo(ECommandType cmdType, Action<CommandRecord> undoAct)
        {
            if (cmdType == ECommandType.None) { return; }
            var (undo, redo) = GetRegistedCommand(cmdType);
            if (undo == null) {
                _commandActions[cmdType] = (undoAct, redo);
            }
            else
                throw new Exception($"对命令历史中的 {cmdType} 已经注册过 undo 方法");
        }

        public void RegisterCommandRedo(ECommandType cmdType, Action<CommandRecord> redoAct)
        {
            if (cmdType == ECommandType.None) { return; }
            var (undo, redo) = GetRegistedCommand(cmdType);
            if (redo == null)
            {
                _commandActions[cmdType] = (undo, redoAct);
            }
            else
                throw new Exception($"对命令历史中的 {cmdType} 已经注册过 redo 方法");
        }

        public void RegisterCommandActions(ECommandType cmdType, Action<CommandRecord> undoAct, Action<CommandRecord> redoAct)
        {
            if (cmdType == ECommandType.None) { return; }
            var (undo, redo) = GetRegistedCommand(cmdType);
            if (undo == null && redo == null)
            {
                _commandActions[cmdType] = (undoAct, redoAct);
            }
            else if (undo == null)
            {
                throw new Exception($"对命令历史中的 {cmdType} 已经注册过 undo 方法");
            }
            else if (redo == null)
            {
                throw new Exception($"对命令历史中的 {cmdType} 已经注册过 redo 方法");
            }
        }

        public void AddRecord(CommandRecord cmdRec)
        {
            _cmdHistory.AddRecord(cmdRec);
        }

        public void ClearHistroy()
        {
            _cmdHistory.Clear();
        }

        public void Undo()
        {
            var prevCmd = _cmdHistory.PreviousRecord();
            if (prevCmd != null)
            {
                var (undo, redo) = GetRegistedCommand(prevCmd.CmdType);
                undo?.Invoke(prevCmd);
            }

            //var prevCmd = _cmdHistory.PreviousRecord();
            //if (prevCmd != null)
            //{
            //    switch (prevCmd.CmdType)
            //    {
            //        case ECommandType.None:
            //            break;
            //        case ECommandType.CreateNode:
            //            Undo_CreateNode(prevCmd as Cmd_CreateNode);
            //            break;
            //        case ECommandType.DeleteNodes:
            //            Undo_DeleteNodes(prevCmd as Cmd_DeleteNodes);
            //            break;
            //        case ECommandType.CreateLink:
            //            Undo_CreateLink(prevCmd as Cmd_CreateLink);
            //            break;
            //        case ECommandType.DeleteLinks:
            //            Undo_DeleteLinks(prevCmd as Cmd_DeleteLinks);
            //            break;
            //        case ECommandType.MoveNodes:
            //            Undo_MoveNodes(prevCmd as Cmd_MoveNods);
            //            break;
            //        case ECommandType.IncreaseSubPort:
            //            Undo_IncreaseSubPort(prevCmd as Cmd_IncreaseSubPort);
            //            break;
            //        case ECommandType.DeleteSubPort:
            //            Undo_DeleteSubPort(prevCmd as Cmd_DeleteSubPort);
            //            break;
            //        case ECommandType.ChangePortValue:
            //            Undo_ChangePortValue(prevCmd as Cmd_ChangePortValue);
            //            break;
            //        case ECommandType.PasteDagData:
            //            Undo_PasteDagData(prevCmd as Cmd_PasteDagData);
            //            break;
            //        default:
            //            break;
            //    }
            //}
        }

        public void Redo()
        {
            var nextCmd = _cmdHistory.NextRecord();
            if (nextCmd != null)
            {
                var (undo, redo) = GetRegistedCommand(nextCmd.CmdType);
                redo?.Invoke(nextCmd);
            }

            //var nextCmd = _cmdHistory.NextRecord();
            //if (nextCmd != null)
            //{
            //    switch (nextCmd.CmdType)
            //    {
            //        case ECommandType.None:
            //            break;
            //        case ECommandType.CreateNode:
            //            Redo_CreateNode(nextCmd as Cmd_CreateNode);
            //            break;
            //        case ECommandType.DeleteNodes:
            //            Redo_DeleteNodes(nextCmd as Cmd_DeleteNodes);
            //            break;
            //        case ECommandType.CreateLink:
            //            Redo_CreateLink(nextCmd as Cmd_CreateLink);
            //            break;
            //        case ECommandType.DeleteLinks:
            //            Redo_DeleteLinks(nextCmd as Cmd_DeleteLinks);
            //            break;
            //        case ECommandType.MoveNodes:
            //            Redo_MoveNodes(nextCmd as Cmd_MoveNods);
            //            break;
            //        case ECommandType.IncreaseSubPort:
            //            Redo_IncreaseSubPort(nextCmd as Cmd_IncreaseSubPort);
            //            break;
            //        case ECommandType.DeleteSubPort:
            //            Redo_DeleteSubPort(nextCmd as Cmd_DeleteSubPort);
            //            break;
            //        case ECommandType.ChangePortValue:
            //            Redo_ChangePortValue(nextCmd as Cmd_ChangePortValue);
            //            break;
            //        case ECommandType.PasteDagData:
            //            Redo_PasteDagData(nextCmd as Cmd_PasteDagData);
            //            break;
            //        default:
            //            break;
            //    }
            //}
        }

        //void Undo_CreateNode(Cmd_CreateNode cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Undo_CreateNode(cmd);
        //    }
        //}

        //void Redo_CreateNode(Cmd_CreateNode cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Redo_CreateNode(cmd);
        //    }
        //}

        //void Undo_DeleteNodes(Cmd_DeleteNodes cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Undo_DeleteNodes(cmd);
        //    }
        //}

        //void Redo_DeleteNodes(Cmd_DeleteNodes cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Redo_DeleteNodes(cmd);
        //    }
        //}

        //void Undo_CreateLink(Cmd_CreateLink cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Undo_CreateLink(cmd);
        //    }
        //}

        //void Redo_CreateLink(Cmd_CreateLink cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Redo_CreateLink(cmd);
        //    }
        //}

        //void Undo_DeleteLinks(Cmd_DeleteLinks cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Undo_DeleteLinks(cmd);
        //    }
        //}

        //void Redo_DeleteLinks(Cmd_DeleteLinks cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Redo_DeleteLinks(cmd);
        //    }
        //}

        //void Undo_MoveNodes(Cmd_MoveNods cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Undo_MoveNodes(cmd);
        //    }
        //}

        //void Redo_MoveNodes(Cmd_MoveNods cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Redo_MoveNodes(cmd);
        //    }
        //}

        //void Undo_IncreaseSubPort(Cmd_IncreaseSubPort cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Undo_IncreaseSubPort(cmd);
        //    }
        //}

        //void Redo_IncreaseSubPort(Cmd_IncreaseSubPort cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Redo_IncreaseSubPort(cmd);
        //    }
        //}

        //void Undo_DeleteSubPort(Cmd_DeleteSubPort cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Undo_DeleteSubPort(cmd);
        //    }
        //}

        //void Redo_DeleteSubPort(Cmd_DeleteSubPort cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Redo_DeleteSubPort(cmd);
        //    }
        //}

        //void Undo_ChangePortValue(Cmd_ChangePortValue cmd)
        //{
        //    if (cmd!= null)
        //    {
        //        _mainWinVM.DagVM.Undo_ChangePortValue(cmd);
        //    }
        //}

        //void Redo_ChangePortValue(Cmd_ChangePortValue cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Redo_ChangePortValue(cmd);
        //    }
        //}

        //void Undo_PasteDagData(Cmd_PasteDagData cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Undo_PasteDagData(cmd);
        //    }
        //}

        //void Redo_PasteDagData(Cmd_PasteDagData cmd)
        //{
        //    if (cmd != null)
        //    {
        //        _mainWinVM.DagVM.Redo_PasteDagData(cmd);
        //    }
        //}
    }
}
